﻿using Microsoft.SharePoint;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace WindStyle.SPEntity
{
    internal class MappingHelper
    {
        internal static void PopulateEntity(SPListItem item, Entity entity, SPRegionalSettings regionalSettings)
        {
            var type = entity.GetType();
            var properties = type.GetProperties();
            foreach (var property in properties)
            {
                var fieldAttributes = property.GetCustomAttributes(typeof(Attributes.FieldAttribute), true);
                if (fieldAttributes.Any())
                {
                    var attribute = fieldAttributes.First() as Attributes.FieldAttribute;
                    var fieldValue = item[attribute.FieldName];

                    var context = new Converters.ConversionContext()
                    {
                        Item = item,
                        RegionalSettings = regionalSettings,
                        Attribute = attribute
                    };
                    object propertyValue = null;

                    var propertyType = property.PropertyType;
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        propertyType = Nullable.GetUnderlyingType(propertyType);

                    var converter = ConverterProvider.GetConverterForProperty(propertyType);
                    if (converter != null)
                        propertyValue = converter.ToPropertyValue(fieldValue, propertyType, context);
                    else if (fieldValue != null)
                    {
                        var field = item.Fields.GetFieldByInternalName(attribute.FieldName);
                        if (propertyType.IsAssignableFrom(field.FieldValueType))
                            propertyValue = fieldValue;
                        else
                        {
                            converter = ConverterProvider.GetConverterForField(field.FieldValueType);
                            if (converter == null)
                                converter = ConverterProvider.GetConverterForField(field.GetType());
                            if (converter != null)
                                propertyValue = converter.ToPropertyValue(fieldValue, propertyType, context);
                        }
                    }

                    if (propertyValue != null)
                    {
                        try
                        {
                            property.SetValue(entity, propertyValue, null);
                        }
                        catch (Exception e)
                        {
                            throw new InvalidCastException(string.Format("Cannot assign value [{0}] to property [{1}]",
                                propertyValue.ToString(),
                                property.Name), e);
                        }
                    }
                }
            }
        }

        internal static void PopulateListItem(SPListItem item, Entity entity, SPRegionalSettings regionalSettings)
        {
            var type = entity.GetType();
            var properties = type.GetProperties();
            foreach (var property in properties)
            {
                var fieldAttributes = property.GetCustomAttributes(typeof(Attributes.FieldAttribute), true);
                if (fieldAttributes.Any())
                {
                    var attribute = fieldAttributes.First() as Attributes.FieldAttribute;
                    if (attribute.Mode == Attributes.MappingMode.ReadOnly)
                        continue;

                    var field = item.Fields.GetFieldByInternalName(attribute.FieldName);
                    var propertyValue = property.GetValue(entity, null);

                    var context = new Converters.ConversionContext()
                    {
                        Item = item,
                        RegionalSettings = regionalSettings,
                        Attribute = attribute
                    };
                    object fieldValue = null;

                    var propertyType = property.PropertyType;
                    if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        propertyType = Nullable.GetUnderlyingType(propertyType);

                    var converter = ConverterProvider.GetConverterForProperty(propertyType);
                    if (converter != null)
                        fieldValue = converter.ToFieldValue(propertyValue, field.FieldValueType, context);
                    else if (propertyValue != null)
                    {
                        if (field.FieldValueType.IsAssignableFrom(propertyType))
                            fieldValue = propertyValue;
                        else
                        {
                            converter = ConverterProvider.GetConverterForField(field.FieldValueType);
                            if (converter == null)
                                converter = ConverterProvider.GetConverterForField(field.GetType());
                            if (converter != null)
                                fieldValue = converter.ToFieldValue(propertyValue, field.FieldValueType, context);
                        }
                    }

                    item[attribute.FieldName] = fieldValue;
                }
            }
        }
    }
}
